package top.oyyf.call_back_demo.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import top.oyyf.call_back_demo.entity.CommonEventData;
import top.oyyf.call_back_demo.entity.TextMsgEventData;
import top.oyyf.call_back_demo.entity.UserEventData;
import top.oyyf.call_back_demo.utils.aes.AesException;
import top.oyyf.call_back_demo.utils.aes.WXBizMsgCrypt;
import top.oyyf.call_back_demo.utils.xml.XMLUtil;
@Slf4j
@Service
public class CallbackService {

    @Value("${qywx.corpId}")
    private String corpId;

    @Value("${qywx.call-back.token}")
    private String callBackToken;
    @Value("${qywx.call-back.encodingAESKey}")
    private String callBackEncodingAESKey;

    public String callback(String msgSignature, String timestamp, String nonce, String echoStr,String xml) {
        if (echoStr==null&&xml==null){
            return "解析内容为空，解析失败";
        }
        if (msgSignature==null||timestamp==null||nonce==null){
            return "辅助解析参数为空，解析失败";
        }

        String result = "成功";
        try {
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(callBackToken, callBackEncodingAESKey, corpId);
            //这里注意在配置url时企业微信会调用一次该接口，此时echoStr是有值的
            //为了通过企业微信的校验这里需要解密并且将明文返回
            if (echoStr!=null&&!echoStr.isEmpty()){
                //调用工具包解密
                return wxcpt.VerifyURL(msgSignature, timestamp, nonce, echoStr);
            }else {
                //如果echoStr没值，那肯定是企业的业务回调了
                String plainXml = wxcpt.DecryptMsg(msgSignature, timestamp, nonce, xml);
                log.info("plainXml:{}",plainXml);

                //企业微信回调的明文是xml,下面我用javax.xml来做一个解析。
                CommonEventData xmlObject = XMLUtil.convertXmlStrToObject(CommonEventData.class, plainXml);
                //因为企业微信有各种各样的回调xml类型，因此需要做抽象类，并以对应子类返回数据
                if ("text".equals(xmlObject.getMsgType())){
                    log.info("text");
                    //文本消息回调的业务逻辑
                    TextMsgEventData textMsgEventData = XMLUtil.convertXmlStrToObject(TextMsgEventData.class, xml);
                    log.info("textMsgEventData:{}",textMsgEventData);

                    String sRespData = "<xml>\n" +
                            "\t<ToUserName>\n" +
                            "\t\t<![CDATA[%s]]>\n" +
                            "\t</ToUserName>\n" +
                            "\t<FromUserName>\n" +
                            "\t\t<![CDATA[%s]]>\n" +
                            "\t</FromUserName>\n" +
                            "\t<CreateTime>%s</CreateTime>\n" +
                            "\t<MsgType>\n" +
                            "\t\t<![CDATA[text]]>\n" +
                            "\t</MsgType>\n" +
                            "\t<Content>\n" +
                            "\t\t<![CDATA[%s]]>\n" +
                            "\t</Content>\n" +
                            "\t<MsgId>%s</MsgId>\n" +
                            "\t<AgentID>%s</AgentID>\n" +
                            "</xml>";
                    sRespData = String.format(sRespData, "ZhangZhen", xmlObject.getToUserName(),
                            timestamp, "回应刚才的消息:" + xmlObject.getContent(), xmlObject.getMsgId(), xmlObject.getAgentId());
                    log.info("sRespData:{}", sRespData);
                    result = wxcpt.EncryptMsg(sRespData, timestamp, nonce);
                }
                //如果你需要加其它业务逻辑需要自己建BaseEventData的子类来对应，当然这只是我使用了javax.xml来解析xml的案例，有更好用的xml包可以替换
                if ("event".equals(xmlObject.getMsgType())){
                    //事件消息回调的业务逻辑,审批和成员变动都是该类型，该类型的消息还有很多不同内容的xml需要特别注意（用我这个方法就需要建很多的子类来对应）
                    log.info("event");
                    //这里我们忽略Event的类型直接用ChangeType来判断使用哪个类进行封装
                    switch(xmlObject.getChangeType()){
                        case "create_user":
                        case "update_user":
                        case "delete_user":
                            UserEventData userEventData = XMLUtil.convertXmlStrToObject(UserEventData.class, xml);
                            log.info("userEventData:{}",userEventData);

                    }
                }
            }
        } catch (AesException e) {
            log.error("", e);
        }
        return result;
    }
}
